package com.bestcem.xm.user.service.impl;

import cn.hutool.core.lang.ObjectId;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.constant.RegTypes;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.AuthErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.common.core.uitls.TransactionUtils;
import com.bestcem.xm.user.config.properties.SampleProperties;
import com.bestcem.xm.user.config.properties.SettingProperties;
import com.bestcem.xm.user.config.properties.UserEmailProperties;
import com.bestcem.xm.user.config.properties.info.SampleOrgInfo;
import com.bestcem.xm.user.constant.BusinessConstant;
import com.bestcem.xm.user.constant.CommonConstant;
import com.bestcem.xm.user.constant.UserCacheKeyConstant;
import com.bestcem.xm.user.enums.*;
import com.bestcem.xm.user.grpc.client.BpProjectGrpcService;
import com.bestcem.xm.user.grpc.client.IndustryGrpcService;
import com.bestcem.xm.user.grpc.client.OmUserGrpcService;
import com.bestcem.xm.user.grpc.client.PackageGrpcService;
import com.bestcem.xm.user.grpc.client.dto.IndustryDTO;
import com.bestcem.xm.user.grpc.client.dto.IndustryPrincipalDTO;
import com.bestcem.xm.user.grpc.client.dto.PackageDTO;
import com.bestcem.xm.user.mq.send.biz.UserMessageSendService;
import com.bestcem.xm.user.service.*;
import com.bestcem.xm.user.service.dto.redis.UserRegisterDTO;
import com.bestcem.xm.user.service.dto.role.UserRoleDTO;
import com.bestcem.xm.user.service.dto.user.*;
import com.bestcem.xm.user.service.third.PhoneService;
import com.bestcem.xm.user.util.UserAsyncUtil;
import com.bestcem.xm.user.util.business.DataBaseUtil;
import com.bestcem.xm.user.util.business.PwdUtil;
import com.bestcem.xm.user.util.business.UserCacheUtil;
import com.bestcem.xm.user.util.business.UserUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;

import javax.annotation.Resource;
import java.sql.SQLIntegrityConstraintViolationException;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.*;
import java.util.stream.Collectors;

import static com.bestcem.xm.user.constant.SmsConstant.*;


/**
 * 用户公司业务Service
 *
 * @author wangyunyun <yunyun.wang@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/8 14:48
 */
@Slf4j
@Service
public class UserOrgBusinessServiceImpl implements UserOrgBusinessService {

    @Resource
    private SettingProperties settingProperties;

    @Resource
    private UserCacheUtil userCacheUtil;

    @Resource
    private SampleProperties sampleProperties;

    @Autowired
    private OrganizationService organizationService;
    @Lazy
    @Autowired
    private UserAsyncUtil userAsyncUtil;

    @Autowired
    private UserService userService;

    @Autowired
    private UserGroupBusinessService userGroupBusinessService;

    @Autowired
    private UserUserRoleService userUserRoleService;

    @Autowired
    private OmUserGrpcService omUserGrpcService;

    @Autowired
    private PackageGrpcService packageGrpcService;

    @Autowired
    private IndustryGrpcService industryGrpcService;

    @Autowired
    private SequenceService sequenceService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private UserBusinessService userBusinessService;

    @Autowired
    private UserAuthService userAuthService;

    @Autowired
    private UserUserAuthLogService userUserAuthLogService;

    @Resource
    private UserPrivateKeyBusinessService userPrivateKeyBusinessService;

    @Autowired
    private UserSmtpService userSmtpService;

    //@Autowired
    //private OrganizationMessageSender organizationMessageSender;

    @Resource
    private UserMessageSendService userMessageSendService;

    @Autowired
    private UserEmailProperties userEmailProperties;

    @Autowired
    private BpProjectGrpcService bpProjectGrpcService;

    @Autowired
    private UserUtil userUtil;

    @Resource
    private PlatformTransactionManager xmTransactionManager;

    @Autowired
    private PhoneService phoneService;

    @Value("${app.user.sensitive-word.enable:true}")
    private Boolean sensitiveWordEnable;

    @Override
    public void createPreOrgForRegister() {
        // 获取类型为基础试用版的套餐信息
        PackageDTO freeTrialPackage = packageGrpcService.getByType(PackageTypeEnum.FREE_TRIAL.getType());
        if (freeTrialPackage == null) {
            log.error("预创建注册公司失败. 查询不到对应的套餐信息: ttype = [基础试用版]");
            return;
        }

        // 获取类型为基础版的套餐信息
        PackageDTO freePackage = packageGrpcService.getByType(PackageTypeEnum.FREE.getType());
        if (freePackage == null) {
            log.error("预创建注册公司失败. 查询不到对应的套餐信息: ttype = [基础版]");
            return;
        }

        // 获取并校验需要预创建的sample公司集合
        List<SampleOrgInfo> orgList = sampleProperties.getOrgList();
        if (CollectionUtils.isEmpty(orgList)) {
            log.error("预创建注册公司失败. 未配置 app.user.sample.orgList");
            return;
        }

        // 遍历需要预创建的sample公司集合
        for (SampleOrgInfo sampleOrgDTO : orgList) {
            // 根据demo orgCode删除对应的预创建公司的缓存
            if (StringUtils.isBlank(sampleOrgDTO.getOrgCode())) {
                log.error("预创建注册公司失败. 未配置 sample orgCode: sampleOrgDTO = [{}]", JSON.toJSONString(sampleOrgDTO));
                continue;
            }
            userCacheUtil.delete(UserCacheKeyConstant.USER_PRE_CREATE_DEMO_ORG_CODE, sampleOrgDTO.getOrgCode().toUpperCase());

            // 如果预创建公司数量不大于0,则直接跳过
            if (sampleOrgDTO.getPreCreateNum() == null || NumberUtils.INTEGER_ZERO.compareTo(sampleOrgDTO.getPreCreateNum()) >= 0) {
                continue;
            }

            // 根据sample公司, 预创建对应的注册公司
            this.createPreFreeOrgBySampleOrg(sampleOrgDTO, freeTrialPackage, freePackage);
        }
    }

    @Override
    public ServiceResult<String> createFreeOrg(OrganizationDTO organizationDTO, String sampleOrgCode) {
        // 校验公司code
        ServiceResult<String> checkOrgCodeRt = this.checkOrgCode(organizationDTO.getCode());
        if (!checkOrgCodeRt.isSuccess()) {
            return checkOrgCodeRt;
        }

        // 如果免费版公司来源不存在则设置默认值
        if (organizationDTO.getSource() == null) {
            organizationDTO.setSource(OrgSourceEnum.REGISTER.getType());
        }

        // 设置归属地
        String location = phoneService.getPhoneLocation(organizationDTO.getAdminPhone());
        organizationDTO.setLocation(location);
        // 创建公司
        organizationDTO.setCheckSmtpId(DataBaseUtil.generateId());
        ServiceResult<String> orgCreateRt = organizationService.insert(organizationDTO);
        if (!orgCreateRt.isSuccess()) {
            return orgCreateRt;
        }
        // 创建系统管理员角色和对应的权限
        ServiceResult<UserRoleDTO> createAdminRoleRt = roleService.createAdminRole(organizationDTO);
        if (!createAdminRoleRt.isSuccess()) {
            return ServiceResult.fail(createAdminRoleRt.getMsg());
        }

        // 创建系统邮箱配置, 更新公司的系统邮箱配置
        userSmtpService.createSystemSmtp(organizationDTO.getOrgId(), organizationDTO.getCheckSmtpId());
        // 创建公司公私钥
        userPrivateKeyBusinessService.createOrgPrivateKeyInfo(organizationDTO.getOrgId());

        // 创建免费账户的负责人和关联人
        IndustryPrincipalDTO industryPrincipalDTO = omUserGrpcService.getIndustryPrincipal(organizationDTO.getIndustryId());
        if (industryPrincipalDTO != null && StringUtils.isNotBlank(industryPrincipalDTO.getId())) {
            List<String> relatedOps = new ArrayList<>();
            relatedOps.add(industryPrincipalDTO.getId());
            omUserGrpcService.createOrgRelatedOp(organizationDTO.getOrgId(), industryPrincipalDTO.getId(), relatedOps);
        }

        // 发送mq: 1.创建公司 2.创建免费公司
        userMessageSendService.userOrgCreate(organizationDTO.getOrgId());
        //organizationMessageSender.userFreeOrgCreate(organizationDTO.getOrgId());

        return ServiceResult.success();
    }

    /**
     * 新建公司 copy sample
     *
     * @param organizationDTO
     * @param sampleOrgCode
     * @return ServiceResult<String>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @version v1.0
     * @date 2022/3/11 17:35
     */
    @Override
    @Async
    public ServiceResult<Void> copySample(OrganizationDTO organizationDTO, String sampleOrgCode) {
        // 查询sample_org
        sampleOrgCode = StringUtils.isNotBlank(sampleOrgCode) ? sampleOrgCode : sampleProperties.getDefaultOrg().getOrgCode();
        // 查询并校验样本公司
        OrganizationDTO sampleOrg = organizationService.selectByOrgCode(sampleOrgCode).getData();
        if (sampleOrg == null) {
            log.error("copySample失败. sampleOrg查询失败. sampleOrgCode: [{}]. ", sampleOrgCode);
            return ServiceResult.fail("copySample失败");
        }

        // group_copy group_level_copy sequence_copy[group seq起始值]
        ServiceResult<Map<String, String>> groupCopySampleRt = userGroupBusinessService.copySample(sampleOrg.getOrgId(), organizationDTO.getOrgId());
        if (!groupCopySampleRt.isSuccess()) {
            log.error("copySample失败. groupCopySampleRt: [{}]. srcOrgId = [{}], dstOrgId = [{}]",
                    JSON.toJSONString(groupCopySampleRt), sampleOrg.getOrgId(), organizationDTO.getOrgId());
            return ServiceResult.fail("copySample失败.");
        }

        // copy_role 复制源公司的角色和角色权限, 以及特殊的角色首页设置
        ServiceResult<String> roleCopySampleRt = roleService.copySample(sampleOrg.getOrgId(), organizationDTO);
        if (!roleCopySampleRt.isSuccess()) {
            log.error("copySample失败. roleCopySampleRt: [{}]. srcOrgId = [{}], dstOrgId = [{}]",
                    JSON.toJSONString(roleCopySampleRt), sampleOrg.getOrgId(), organizationDTO.getOrgId());
            return ServiceResult.fail("copySample失败");
        }

        // 执行问卷项目的copy_sample
        Boolean qdesCopySampleRt = bpProjectGrpcService.qdesCopySample(sampleOrg.getOrgId(), organizationDTO.getOrgId());
        if (qdesCopySampleRt == null || !qdesCopySampleRt) {
            log.error("copySample失败. qdesCopySample. srcOrgId = [{}], dstOrgId = [{}]", sampleOrg.getOrgId(), organizationDTO.getOrgId());
        }
        return ServiceResult.fail("copySample失败");
    }

    @Override
    public ServiceResult<String> createFreeSystemUser(UserDTO userDTO) {
        // 设置是否是内部员工
        if (StringUtils.isNotBlank(userDTO.getPhone())) {
            boolean checkUserIsInner = userUtil.checkUserIsInner(userDTO.getPhone(), "", "");
            userDTO.setInnerFlag(checkUserIsInner ? UserInnerFlagEnum.INNER.getType() : UserInnerFlagEnum.OUTTER.getType());
        }
        userDTO.setStatus(UserStatusEnum.ACTIVATED.getStatus());
        userDTO.setEdition(UserEditionEnum.FREE.getType());

        // 创建用户
        ServiceResult<String> userIdResult = userService.insert(userDTO);
        // 创建用户与角色的关联关系
        UserUserRoleDTO userUserRoleDTO = new UserUserRoleDTO();
        // 设置公司的系统管理员角色
        userUserRoleDTO.setRoleId(roleService.getAdminRole(userDTO.getOrgId()).getData());
        userUserRoleDTO.setUserId(userIdResult.getData());
        userUserRoleDTO.setOrgId(userDTO.getOrgId());
        userUserRoleService.insert(userUserRoleDTO);


        // 更新公司用户数消费额
        userService.updateUserConsumption(userDTO.getOrgId(), NumberUtils.INTEGER_ONE);

        return ServiceResult.success();
    }

    @Override
    public ServiceResult<String> checkOrgCode(String code) {
        // 长度不能少于2
        if (StringUtils.isBlank(code) || code.length() < 2) {
            return ServiceResult.fail(UserErrorEnum.ORG_CODE_TOO_SIMPLE, String.format("code[%s] is too short", code));
        }
        // 不能为禁用的公司代码
        if (settingProperties.getForbiddenOrgCodeList().contains(code)) {
            return ServiceResult.fail(UserErrorEnum.ORG_CODE_FORMAT,
                    String.format("code[%s] cannot be %s", code, JSON.toJSONString(settingProperties.getForbiddenOrgCodeList())));
        }
        // 只能包含中英文/数字/中划线
        if (!code.matches(RegTypes.ORG_CODE)) {
            return ServiceResult.fail(UserErrorEnum.ORG_CODE_FORMAT, String.format("code[%s] must be make up of lowercase letters, digits or -", code));
        }
        return ServiceResult.success();
    }

    @Override
    public ServiceResult<JSONObject> registerOrg(OrgRegisterDTO orgRegisterDTO, UserRegisterDTO userRegisterDTO, IndustryDTO industryDTO) {
        // 获取类型为基础试用版的套餐信息
        ServiceResult<PackageDTO> freeTrialPackageRt = packageGrpcService.getByTypeByBusiness(PackageTypeEnum.FREE_TRIAL.getType());
        if (!freeTrialPackageRt.isSuccess()) {
            return ServiceResult.fail(null, freeTrialPackageRt.getMsg(), freeTrialPackageRt.getErrorCode());
        }
        PackageDTO freeTrialPackageDTO = freeTrialPackageRt.getData();

        // 创建公司
        SampleOrgInfo sampleOrgInfo = sampleProperties.getByIndustryCode(industryDTO.getCode());
        String sampleOrgCode = sampleOrgInfo != null ? sampleOrgInfo.getOrgCode() : null;

        if (log.isInfoEnabled()) {
            log.info("[USER] registerOrg sampleOrgCode:{} industryDTO:{}", sampleOrgCode, industryDTO);
        }

        // 获取预创建公司
        String orgId = "";
        if (StringUtils.isNotEmpty(sampleOrgCode)) {
            orgId = userCacheUtil.leftPop(userCacheUtil
                    .buildKey(UserCacheKeyConstant.USER_PRE_CREATE_DEMO_ORG_CODE, sampleOrgCode.toUpperCase()));
        }
        // 设置参数
        Date now = DataBaseUtil.getDate();
        // 设置用户参数
        UserDTO userDTO = new UserDTO();
        userDTO.setPhone(userRegisterDTO.getPhone());
        userDTO.setUserName(orgRegisterDTO.getUserName());
        userDTO.setName(orgRegisterDTO.getName());
        userDTO.setSalt(PwdUtil.genSalt());
        userDTO.setPassword(PwdUtil.getEncodePwd(orgRegisterDTO.getPassword(), userDTO.getSalt()));
        userDTO.setWxUnionid(userRegisterDTO.getWxUnionid());
        userDTO.setWxOffiOpenid(userRegisterDTO.getWxOffiOpenid());
        userDTO.setWxNickname(userRegisterDTO.getWxNickname());
        userDTO.setAcceptFlag(Boolean.TRUE.equals(orgRegisterDTO.getHasAcceptPolicy()) ? UserAccpectFlagEnum.ACCPECT.getType() : UserAccpectFlagEnum.NOT_ACCPECT.getType());
        userDTO.setRegisterIp(orgRegisterDTO.getIpAddress());
        userDTO.setUpdateTime(now);
        userDTO.setEmail(orgRegisterDTO.getEmail());

        // 设置是否是内部员工
        if (StringUtils.isNotBlank(userDTO.getPhone())) {
            boolean checkUserIsInner = userUtil.checkUserIsInner(userDTO.getPhone(), "", "");
            userDTO.setInnerFlag(checkUserIsInner ? UserInnerFlagEnum.INNER.getType() : UserInnerFlagEnum.OUTTER.getType());
        }

        // 设置公司参数
        OrganizationDTO organizationDTO = new OrganizationDTO();
        organizationDTO.setCode(this.genOrgCode());
        organizationDTO.setIndustryId(industryDTO.getIndustryId());
        organizationDTO.setName(orgRegisterDTO.getOrgName());
        organizationDTO.setDistribution(industryDTO.getSalesEmails().get(0).split("@")[0]);
        organizationDTO.setAdminEmail(userDTO.getEmail());
        organizationDTO.setAdminName(userDTO.getUserName());
        organizationDTO.setAdminPhone(userDTO.getPhone());
        organizationDTO.setInnerFlag(userDTO.getInnerFlag());
        organizationDTO.setStatus(OrganizationStatusEnum.ACTIVATED.getStatus());
        organizationDTO.setCreateTime(now);
        organizationDTO.setUpdateTime(organizationDTO.getCreateTime());
        organizationDTO.setScenarioId(orgRegisterDTO.getScenarioId());
        organizationDTO.setAdminEmail(orgRegisterDTO.getEmail());
        organizationDTO.setSeoSource(orgRegisterDTO.getSource());
        organizationDTO.setSensitiveWordEnable(BooleanStatusEnum.toInteger(sensitiveWordEnable));
        if (StringUtils.isNotBlank(orgId)) {
            // 设置参数
            organizationDTO.setOrgId(orgId);

            // 更新用户信息
            // 通过公司id查询公司的系统管理员用户
            UserDTO adminUser = userBusinessService.getAdminUserByOrgId(orgId).getData();
            userDTO.setUserId(adminUser.getUserId());
            userService.updateById(userDTO);

            // 设置预创建的归属地
            String location = phoneService.getPhoneLocation(organizationDTO.getAdminPhone());
            organizationDTO.setLocation(location);
            // 更新公司信息
            organizationService.updateByPrimaryKeySelective(organizationDTO);

            ServiceResult<OrganizationDTO> organizationDTOServiceResult = organizationService.selectByPrimaryKey(orgId);
            organizationDTO = organizationDTOServiceResult.getData();
        } else {
            // 设置参数
            orgId = DataBaseUtil.generateId();
            String userId = DataBaseUtil.generateId();
            userDTO.setUserId(userId);
            userDTO.setOrgId(orgId);
            userDTO.setCreateTime(now);
            organizationDTO.setOrgId(orgId);

            // 获取免费版套餐
            ServiceResult<PackageDTO> freePackageRt = packageGrpcService.getByTypeByBusiness(PackageTypeEnum.FREE.getType());
            if (!freePackageRt.isSuccess()) {
                return ServiceResult.fail(null, freePackageRt.getMsg(), freePackageRt.getErrorCode());
            }
            PackageDTO freePackage = freePackageRt.getData();

            this.setOrgPackageInfo(organizationDTO, freeTrialPackageDTO, freePackage, now);

            ServiceResult<String> createFreeOrgResult = this.createFreeOrg(organizationDTO, sampleOrgCode);
            if (!createFreeOrgResult.isSuccess()) {
                return ServiceResult.fail(null, createFreeOrgResult.getMsg(), createFreeOrgResult.getErrorCode());
            }
            // 创建用户
            this.createFreeSystemUser(userDTO);

            // 开始copy sample
            this.copySample(organizationDTO, sampleOrgCode);
        }

        // 设置返回值
        JSONObject result = new JSONObject();
        result.put(UserDTO.class.getName(), userDTO);
        result.put(OrganizationDTO.class.getName(), organizationDTO);
        result.put(PackageDTO.class.getName(), freeTrialPackageDTO);
        return ServiceResult.success(result);
    }

    /**
     * 校验套餐是否过期
     *
     * @param testExpiryDt 套餐过期时间
     * @param isSuper      是否是超级管理员
     * @return
     */
    private boolean checkTestExpiryDt(LocalDateTime testExpiryDt, boolean isSuper) {
        LocalDateTime currentTime = DateUtil.getCurrentTime();
        return isSuper || Period.between(testExpiryDt.toLocalDate(), currentTime.toLocalDate()).getDays() <= 14;
    }

    /**
     * 根据sample公司, 预创建对应的注册公司
     *
     * @param sampleOrgDTO
     * @param freeTrialPackage
     * @param freePackage
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @version v1.0
     * @date 2022/3/8 16:05
     */
    public void createPreFreeOrgBySampleOrg(SampleOrgInfo sampleOrgDTO, PackageDTO freeTrialPackage, PackageDTO freePackage) {
        // 通过行业code获取行业
        IndustryDTO industryDTO = industryGrpcService.getByCode(sampleOrgDTO.getIndustryCode());

        // 创建配置数量的预创建公司
        for (int i = 0; i < sampleOrgDTO.getPreCreateNum(); i++) {
            // 预创建公司
            try {
                String orgId = this.createPreFreeOrg(sampleOrgDTO.getOrgCode(), industryDTO, freeTrialPackage, freePackage);
                if (StringUtils.isBlank(orgId)) {
                    log.error("根据sample公司, 预创建对应的注册公司失败. industryCode = [{}], orgCode = [{}], i= [{}]", sampleOrgDTO.getIndustryCode(), sampleOrgDTO.getOrgCode(), i);
                    continue;
                }
                if (log.isInfoEnabled()) {
                    log.info("根据sample公司, 预创建对应的注册公司industryCode = [{}], orgCode = [{}], i= [{}],orgId=[{}]", sampleOrgDTO.getIndustryCode(), sampleOrgDTO.getOrgCode(), i, orgId);
                }
                userCacheUtil.leftPush(userCacheUtil
                        .buildKey(UserCacheKeyConstant.USER_PRE_CREATE_DEMO_ORG_CODE, sampleOrgDTO.getOrgCode().toUpperCase()), orgId);
            } catch (Throwable e) {
                log.error("根据sample公司, 预创建对应的注册公司失败. industryCode = [{}], orgCode = [{}]", sampleOrgDTO.getIndustryCode(), sampleOrgDTO.getOrgCode());
                log.error("根据sample公司, 预创建对应的注册公司失败.", e);
            }
        }
    }

    /**
     * 预创建公司
     *
     * @param sampleOrgCode
     * @param industryDTO
     * @param freeTrialPackage
     * @param freePackage
     * @return 公司id
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @version v1.0
     * @date 2022/3/8 16:22
     */
    private String createPreFreeOrg(String sampleOrgCode, IndustryDTO industryDTO, PackageDTO freeTrialPackage, PackageDTO freePackage) {
        // 设置参数
        OrganizationDTO organizationDTO = new OrganizationDTO();
        // 设置公司code
        organizationDTO.setCode(this.genOrgCode());
        organizationDTO.setIndustryId(industryDTO != null ? industryDTO.getIndustryId() : StringUtils.EMPTY);
        Date now = DataBaseUtil.getDate();
        // 设置公司套餐信息
        this.setOrgPackageInfo(organizationDTO, freeTrialPackage, freePackage, now);

        organizationDTO.setCompleteFlag(BooleanStatusEnum.NO.getStatus());
        organizationDTO.setAdminPhone(StringUtils.EMPTY);
        organizationDTO.setAdminName(StringUtils.EMPTY);
        organizationDTO.setAdminEmail(StringUtils.EMPTY);
        organizationDTO.setSource(OrgSourceEnum.REGISTER.getType());
        organizationDTO.setInnerFlag(OrgInnerFlagEnum.OUTTER.getType());
        organizationDTO.setStatus(OrganizationStatusEnum.PRE_CREATED.getStatus());
        organizationDTO.setDeliveryAuthType(OrgDeliveryAuthTypeEnum.LONG_TERM.getType());
        organizationDTO.setSensitiveWordEnable(BooleanStatusEnum.toInteger(sensitiveWordEnable));

        ServiceResult<String> createOrgRt = this.createFreeOrg(organizationDTO, sampleOrgCode);
        if (!createOrgRt.isSuccess()) {
            log.error("预创建公司失败. 创建公司失败,失败原因: [{}]", createOrgRt.getMsg());
            return null;
        }

        UserDTO userDTO = new UserDTO();
        userDTO.setOrgId(organizationDTO.getOrgId());
        userDTO.setUserName("superadmin");
        userDTO.setAcceptFlag(UserAccpectFlagEnum.NOT_ACCPECT.getType());
        userDTO.setStatus(UserStatusEnum.ACTIVATED.getStatus());
        userDTO.setSalt(PwdUtil.genSalt());
        userDTO.setPassword(PwdUtil.getEncodePwd(PwdUtil.genPassword(), userDTO.getSalt()));
        userDTO.setName(StringUtils.EMPTY);
        userDTO.setPhone(StringUtils.EMPTY);
        userDTO.setRegisterIp(StringUtils.EMPTY);
        userDTO.setWxNickname(StringUtils.EMPTY);
        userDTO.setWxOffiOpenid(StringUtils.EMPTY);
        userDTO.setWxUnionid(StringUtils.EMPTY);

        ServiceResult<String> createUserRt = this.createFreeSystemUser(userDTO);
        if (!createOrgRt.isSuccess()) {
            log.error("预创建公司失败. 创建用户失败,失败原因: [{}]", createUserRt.getMsg());
            return null;
        }

        // 开始copy sample
        this.copySample(organizationDTO, sampleOrgCode);

        return organizationDTO.getOrgId();
    }

    /**
     * 设置公司套餐信息
     *
     * @param organizationDTO
     * @param freeTrialPackage
     * @param freePackage
     * @param now
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @version v1.0
     * @date 2022/3/10 19:10
     */
    @Override
    public void setOrgPackageInfo(OrganizationDTO organizationDTO, PackageDTO freeTrialPackage, PackageDTO freePackage, Date now) {
        // 新创建用户 默认套餐为基础试用版 且时间为14天
        organizationDTO.setPackageExpireTime(DateUtils.addDays(now, 14));
        organizationDTO.setPackageId(freeTrialPackage.getPackageId());
        // 免费版功能限制使用时间为30天
        organizationDTO.setFreeExpireTime(DateUtils.addDays(now, 30));
        // 试用套餐到期时间
        organizationDTO.setTrialExpireTime(DateUtils.addDays(now, 14));
        organizationDTO.setTrialPackageId(freeTrialPackage.getPackageId());
        // 正式套餐设置
        organizationDTO.setFormalPackageId(freePackage.getPackageId());
        organizationDTO.setFormalExpireTime(DateUtil.getDate("2099-12-31"));
    }

    @Override
    public ServiceResult<String> createOrganization(OrganizationDTO dto, String password, Integer source, String sourceRemark,
                                                    boolean isSuper, String baseOrgCode) {
        // 校验industry是否存在
        IndustryDTO industryDTO = industryGrpcService.getById(dto.getIndustryId());
        if (Objects.isNull(industryDTO)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, "未找到对应的行业信息");
        }
        // 检验code是否重复
        ServiceResult<Boolean> existsResult = organizationService.existsByCode(dto.getCode());
        if (existsResult.isSuccess() && Boolean.TRUE.equals(existsResult.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.DUPLICATE, "公司代号重复");
        }
        List<ServiceResult<String>> resultList = new ArrayList<>();
        // 设置baseorgcode和parentId
        if (StringUtils.isBlank(baseOrgCode)) {
            SampleOrgInfo sampleOrgInfo = sampleProperties.getByIndustryCodeAndDefault(industryDTO.getCode());
            baseOrgCode = sampleOrgInfo.getOrgCode();
        } else {
            OrganizationDTO sampleOrg = organizationService.selectByOrgCode(baseOrgCode).getData();
            if (Objects.nonNull(sampleOrg)) {
                dto.setParentId(sampleOrg.getOrgId());
            }
        }

        // 数据操作
        TransactionUtils.doTransaction(xmTransactionManager, () -> {
            ServiceResult<String> createResult = createOrg(dto, password, source, sourceRemark, isSuper);
            resultList.add(createResult);
            return createResult.isSuccess();
        });
        if (CollectionUtils.isEmpty(resultList)) {
            return ServiceResult.fail(ResourceErrorCodeEnum.DB_WRITE_FAIL, "创建机构失败");
        }

        ServiceResult<String> result = resultList.get(0);
        if (result.isSuccess()) {
            String orgId = result.getData();
            // 更新租户用户数消费额
            userService.updateUserConsumption(orgId, 1);
            // 发送创建公司消息
            userMessageSendService.userOrgCreate(orgId);
            //organizationMessageSender.userFreeOrgCreate(orgId);

            // copysample
            if (StringUtils.isNotBlank(baseOrgCode)) {
                this.copySample(dto, baseOrgCode);
            }
        }
        return result;
    }

    private ServiceResult<String> createOrg(OrganizationDTO dto, String password, Integer source, String sourceRemark,
                                            boolean isSuper) {
        if (Objects.isNull(dto)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "公司信息不能为空");
        }
        if (Objects.isNull(dto.getSource())) {
            dto.setSource(source);
        }
        if (StringUtils.isBlank(dto.getSourceRemark())) {
            dto.setSourceRemark(sourceRemark);
        }
        // 兼容以前的，需要修改
        if (StringUtils.isNotBlank(dto.getPackageId())) {
            dto.setFormalPackageId(dto.getPackageId());
        }
        if (Objects.nonNull(dto.getPackageExpireTime())) {
            dto.setFormalExpireTime(dto.getPackageExpireTime());
        }
        dto.setPackageId(dto.getFormalPackageId());
        dto.setPackageExpireTime(dto.getFormalExpireTime());

        // 参数校验
        ServiceResult<OrganizationDTO> checkOrgParamResult = checkAndSetOrgParam(dto, isSuper);
        if (!checkOrgParamResult.isSuccess()) {
            return ServiceResult.fail(checkOrgParamResult.getErrorData(), checkOrgParamResult.getMsg());
        }
        dto = checkOrgParamResult.getData();

        // 1. 创建公司
        ServiceResult<OrganizationDTO> company = createCompany(dto, password);
        if (!company.isSuccess() || Objects.isNull(company.getData())) {
            return ServiceResult.fail(company.getErrorData(), company.getMsg());
        }
        // 2. 创建系统邮箱
        String orgId = company.getData().getOrgId();
        UserSmtpDTO userSmtpDTO = new UserSmtpDTO();
        userSmtpDTO.setAccount(userEmailProperties.getDefaultEmail());
        userSmtpDTO.setPassword(userEmailProperties.getDefaultPwd());
        userSmtpDTO.setHost(userEmailProperties.getDefaultHost());
        userSmtpDTO.setPort(userEmailProperties.getDefaultPort());
        userSmtpDTO.setDescription("倍市得系统邮箱");
        userSmtpDTO.setSslFlag(BooleanStatusEnum.YES.getStatus());
        userSmtpDTO.setValidateStatus(UserSmtpValidateStatusEnum.VERIFIED_SUCCESS.getStatus());
        userSmtpDTO.setDeliverFlag(BooleanStatusEnum.NO.getStatus());
        userSmtpDTO.setNoticeFlag(BooleanStatusEnum.YES.getStatus());
        userSmtpDTO.setSystemFlag(BooleanStatusEnum.YES.getStatus());
        userSmtpDTO.setOrgId(orgId);
        ServiceResult<String> result = userSmtpService.insertSelective(userSmtpDTO);
        if (!result.isSuccess() || StringUtils.isBlank(result.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.DB_WRITE_FAIL, "insert smtp into db failed");
        }

        // 3. 更新公司的系统邮箱
        OrganizationDTO updateParam = new OrganizationDTO();
        updateParam.setOrgId(orgId);
        updateParam.setCheckSmtpId(result.getData());
        organizationService.updateByPrimaryKeySelective(updateParam);
        return ServiceResult.success(orgId);
    }

    @Override
    public ServiceResult<List<OrganizationDTO>> listIndustrySampleCodes(List<String> codesList) {
        // 设置查询参数
        Set<String> sampleOrgCode = sampleProperties.getOrgList().stream().map(SampleOrgInfo::getOrgCode).collect(Collectors.toSet());
        if (CollectionUtils.isNotEmpty(codesList)) {
            sampleOrgCode.addAll(codesList);
        }

        // 查询
        return organizationService.listByCodes(new ArrayList<>(sampleOrgCode));
    }

    @Override
    public ServiceResult<Boolean> checkOrgExpire(String orgId) {
        // 校验参数
        if (!ObjectId.isValid(orgId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, "id error");
        }
        OrganizationDTO organizationDTO = organizationService.selectByPrimaryKey(orgId).getData();
        if (organizationDTO == null) {
            return ServiceResult.fail(AuthErrorCodeEnum.ORG_NOT_EXISTS, String.format("org not exist. id = %s", orgId));
        }

        // 查询套餐信息
        if (StringUtils.isBlank(organizationDTO.getPackageId())) {
            return ServiceResult.success(Boolean.FALSE);
        }
        PackageDTO packageDTO = packageGrpcService.getById(organizationDTO.getPackageId());
        if (packageDTO == null || StringUtils.isBlank(packageDTO.getPackageId()) || packageDTO.getEdition() == null) {
            return ServiceResult.success(Boolean.FALSE);
        }

        Date now = DataBaseUtil.getDate();
        if (PackageEditionEnum.PACK_EDITION_FREE.getType().equals(packageDTO.getEdition())) {
            if (DateUtils.addDays(organizationDTO.getCreateTime(), BusinessConstant.ORG_PACK_EDITION_FREE_EXPIRE_DAYS).before(now)) {
                return ServiceResult.success(Boolean.FALSE);
            } else if (organizationDTO.getFreeExpireTime() != null && organizationDTO.getFreeExpireTime().before(now)) {
                return ServiceResult.success(Boolean.FALSE);
            } else {
                return ServiceResult.success(Boolean.TRUE);
            }
        } else if (PackageEditionEnum.PACK_EDITION_ENTERPRISE.getType().equals(packageDTO.getEdition())) {
            return (organizationDTO.getPackageExpireTime() != null && organizationDTO.getPackageExpireTime().before(now))
                    ? ServiceResult.success(Boolean.FALSE) : ServiceResult.success(Boolean.TRUE);
        }

        return ServiceResult.success(Boolean.FALSE);
    }

    @Override
    public ServiceResult<String> createOrgFromBackend(OrganizationDTO dto, String managerEmail, String managerPhone) {
        if (StringUtils.isEmpty(dto.getCode())) {
            dto.setCode(this.genOrgCode());
        }

        String password = PwdUtil.genPassword();
        ServiceResult<String> result = this
                .createOrganization(dto, password, null, null, dto.getCheckExpiry(), dto.getParentCode());
        if (result.isSuccess()) {
            userAsyncUtil.notifyCompanyAcceptByEmail(result.getData(), password, managerEmail, managerPhone, null);
        }
        return result;
    }

    @Override
    public ServiceResult<String> acceptBooking(OrganizationDTO dto, String managerEmail, String managerPhone) {
        if (StringUtils.isEmpty(dto.getCode())) {
            dto.setCode(this.genOrgCode());
        }
        String password = PwdUtil.genPassword();
        ServiceResult<String> result = this
                .createOrganization(dto, password, null, null, true, null);
        if (result.isSuccess()) {
            userAsyncUtil.notifyCompanyAcceptByEmail(result.getData(), password, managerEmail, managerPhone, null);
        }

        return result;
    }

    /**
     * 创建公司信息内部方法
     *
     * @param dto      公司信息
     * @param password 密码
     * @return com.bestcem.xm.util.ServiceResult<com.bestcem.xm.user.service.dto.user.OrganizationDTO>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/05/15 11:12
     */
    private ServiceResult<OrganizationDTO> createCompany(OrganizationDTO dto, String password) {
        /*
         * 相关参数校验设置
         */
        // 如果密码不存在则生成随机密码
        if (StringUtils.isBlank(password)) {
            password = PwdUtil.genPassword();
        } else {
            // 校验密码复杂度
            ServiceResult<String> check = PwdUtil.checkPassword(password);
            if (!check.isSuccess()) {
                return ServiceResult.fail(ValidationErrorCodeEnum.SIMPLE_PASSWD, password + "is too simple");
            }
        }
        // 设置code为小写，检验公司code
        dto.setCode(dto.getCode().toLowerCase());
        ServiceResult<String> checkOrgCodeRt = this.checkOrgCode(dto.getCode());
        if (!checkOrgCodeRt.isSuccess()) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, "code 格式错误");
        }
        // 通过mobile、admin_email 判断是否是内部用户
        if (StringUtils.isNotBlank(dto.getAdminEmail()) && StringUtils.isNotBlank(dto.getAdminPhone())) {
            boolean checkUserIsInner = userUtil.checkUserIsInner(dto.getAdminPhone(), dto.getAdminEmail(), "");
            dto.setInnerFlag(BooleanStatusEnum.toInteger(checkUserIsInner));
        }
        // 设置归属地
        String location = phoneService.getPhoneLocation(dto.getAdminPhone());
        dto.setLocation(location);

        /*
         * 2. 开始创建相关信息
         */
        // 2.1 创建公司
        dto.setStatus(OrganizationStatusEnum.ACTIVATED.getStatus());
        try {
            ServiceResult<String> insertOrgResult = organizationService.insert(dto);
            if (!insertOrgResult.isSuccess()) {
                return ServiceResult.fail(ResourceErrorCodeEnum.WRITE_FAIL, "insert company into db failed");
            }
            dto.setOrgId(insertOrgResult.getData());

        } catch (Exception e) {
            log.error("[USER] insert org failed", e);
            if (e instanceof SQLIntegrityConstraintViolationException) {
                return ServiceResult.fail(ResourceErrorCodeEnum.DUPLICATE, "公司代号重复");
            } else {
                return ServiceResult.fail(ResourceErrorCodeEnum.DB_WRITE_FAIL, "创建公司失败");
            }
        }
        // 2.2 创建系统管理员角色和对应的权限
        ServiceResult<UserRoleDTO> adminRole = roleService.createAdminRole(dto);
        if (!adminRole.isSuccess() || Objects.isNull(adminRole.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.WRITE_FAIL, "insert role into db failed");
        }

        // 2.3 创建用户
        UserDTO userInsert = new UserDTO();
        userInsert.setOrgId(dto.getOrgId());
        userInsert.setName("系统管理员");
        userInsert.setUserName("superadmin");
        userInsert.setEmail(dto.getAdminEmail());
        userInsert.setPhone(dto.getAdminPhone());
        userInsert.setStatus(UserStatusEnum.ACTIVATED.getStatus());
        userInsert.setInnerFlag(UserInnerFlagEnum.INNER.getType());
        ServiceResult<String> userInsertResult = userService.insert(userInsert);
        if (!userInsertResult.isSuccess() || Objects.isNull(userInsertResult.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.WRITE_FAIL, "user role into db failed");
        }

        // 2.4 创建用户的角色信息
        UserUserRoleDTO userUserRoleDTO = new UserUserRoleDTO();
        userUserRoleDTO.setOrgId(dto.getOrgId());
        userUserRoleDTO.setRoleId(adminRole.getData().getRoleId());
        userUserRoleDTO.setUserId(userInsertResult.getData());
        userUserRoleService.insert(userUserRoleDTO);

        // 重置用户密码
        userAuthService.resetPassword(userInsertResult.getData(), password);
        // 创建公司公私钥
        userPrivateKeyBusinessService.createOrgPrivateKeyInfo(dto.getOrgId());

        // 用户注册，创建登录记录
        UserAuthLogDTO userAuthLogDTO = new UserAuthLogDTO();
        userAuthLogDTO.setUserId(userInsertResult.getData());
        userAuthLogDTO.setOrgId(dto.getOrgId());
        userAuthLogDTO.setOpType(UserAuthLogOpTypeEnum.LOGIN.getType());
        userUserAuthLogService.insert(userAuthLogDTO);

        return ServiceResult.success(dto);
    }

    /**
     * 校验公司的参数信息
     *
     * @param dto     公司信息
     * @param isSuper 是否管理员
     * @return com.bestcem.xm.util.ServiceResult<com.bestcem.xm.user.service.dto.user.OrganizationDTO>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/05/15 10:43
     */
    private ServiceResult<OrganizationDTO> checkAndSetOrgParam(OrganizationDTO dto, boolean isSuper) {
        // 参数校验
        if (StringUtils.isBlank(dto.getName())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, ":name is required");
        }
        if (StringUtils.isBlank(dto.getIndustryId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, ":industryId is required");
        }
        if (StringUtils.isBlank(dto.getFormalPackageId())) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, ":formalPackageId is required");
        }
        // 校验套餐时间
        Date expiryDate = dto.getFormalExpireTime();
        if (Objects.isNull(expiryDate)) {
            // 获取今天的0点的日期
            Date nowZero = getTodayZero(new Date());
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(nowZero);
            calendar.add(Calendar.DATE, 14);
            expiryDate = calendar.getTime();
        }
        // 校验正式套餐是否过期
        boolean checkTestExpiryDt = checkTestExpiryDt(DateUtil.toLocalTime(expiryDate), isSuper);
        if (!checkTestExpiryDt) {
            return ServiceResult.fail(ResourceErrorCodeEnum.PERMISSION_DENY, "正式套餐过期时间错误");
        }
        // 校验试用套餐
        if (Objects.nonNull(dto.getTrialExpireTime())) {
            Date testExpiryDate = dto.getTrialExpireTime();
            if (testExpiryDate.after(expiryDate)) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "试用套餐日期不能大于正式套餐日期");
            }
            if (getTodayZero(testExpiryDate).before(getTodayZero(new Date()))) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "试用套餐不能小于今天");
            }
            if (!checkTestExpiryDt(DateUtil.toLocalTime(testExpiryDate), false)) {
                return ServiceResult.fail(ResourceErrorCodeEnum.PERMISSION_DENY, "not is superadmin");
            }
            if (StringUtils.isNotBlank(dto.getTrialPackageId())) {
                dto.setPackageId(dto.getTrialPackageId());
                dto.setPackageExpireTime(dto.getTrialExpireTime());
            }
        }

        if (StringUtils.isBlank(dto.getCode())) {
            dto.setCode(genOrgCode());
        }
        if (Objects.isNull(dto.getCompleteFlag())) {
            dto.setCompleteFlag(BooleanStatusEnum.YES.getStatus());
        }
        if (StringUtils.isBlank(dto.getAdminName())) {
            dto.setAdminName("superadmin");
        }
        // 设置短信单价
        if (Objects.isNull(dto.getSmsPrice())) {
            dto.setSmsPrice(SMS_PRICE_DEFAULT);
        }
        if (dto.getSmsPrice() > SMS_PRICE_MAX) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "The sms_price must lte" + SMS_PRICE_MAX);
        }
        if (dto.getSmsPrice() < SMS_PRICE_MIN) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "The sms_price must lte" + SMS_PRICE_MIN);
        }

        return ServiceResult.success(dto);
    }

    /**
     * 获取指定日期的0点
     *
     * @param date 指定的日期
     * @return java.util.Date
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/05/12 13:51
     */
    private Date getTodayZero(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        return calendar.getTime();
    }

    /**
     * 自动生成公司编码
     *
     * @return String
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/4/16 10:03
     */
    public String genOrgCode() {
        // 生成公司code
        int orgSeq = sequenceService.incrementVersion(UserCacheKeyConstant.ORG_CODE_SEQ);
        return String.format(CommonConstant.ORG_CODE_FORMAT, orgSeq);
    }
}
